package cn.slipi.admin.service.impl;


import cn.slipi.admin.common.exception.base.BizException;
import cn.slipi.admin.common.utils.StrUtils;
import cn.slipi.admin.common.utils.dozer.impl.ConvertBean;
import cn.slipi.admin.dao.TSysMenuMapper;
import cn.slipi.admin.entity.TSysMenu;
import cn.slipi.admin.entity.TSysRoleMenu;
import cn.slipi.admin.service.TSysMenuService;
import cn.slipi.admin.service.TSysRoleMenuService;
import cn.slipi.admin.service.dto.in.m.MenuSaveDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统菜单表 服务实现类
 * </p>
 *
 * @author lee
 * @since 2020-10-09
 */
@Service
public class TSysMenuServiceImpl extends ServiceImpl<TSysMenuMapper, TSysMenu> implements TSysMenuService {
    @Autowired
    private ConvertBean convertBean;
    @Autowired
    private TSysRoleMenuService sysRoleMenuService;

    @Override

    @Transactional(rollbackFor = BizException.class)
    public Integer addMenu(MenuSaveDTO menuSaveDTO) {
        TSysMenu menu = new TSysMenu();
        menu.setTitle(menuSaveDTO.getTitle());
        menu.setName(menuSaveDTO.getName());
        menu.setJump(menuSaveDTO.getJump());
        if (null != menuSaveDTO.getPid() && menuSaveDTO.getPid() > 0) {
            menu.setPid(menuSaveDTO.getPid());
            menu.setLevel(1);
        } else {
            menu.setPid(0);
            menu.setLevel(0);
        }
        menu.setShow(menuSaveDTO.getShow());
        menu.setIcon(StrUtils.isNotBlank(menuSaveDTO.getIcon()) ? menuSaveDTO.getIcon() : "");
        menu.setSort(null != menuSaveDTO.getSort() ? menuSaveDTO.getSort() : 0);
        this.baseMapper.insert(menu);
        return menu.getId();
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Boolean updateMenu(Integer mid, MenuSaveDTO menuSaveDTO) {
        TSysMenu menu = this.getMenuById(mid);
        if (null == menu) {
            throw new BizException(10000, "record.found.not");
        }
        this.convertBean.convertNotNull(menuSaveDTO, menu, false, true);
        this.baseMapper.updateById(menu);
        changeShowStatus(menu, menuSaveDTO.getShow());
        return true;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Boolean deleteMenu(Integer mid) {
        TSysMenu menu = this.getMenuById(mid);
        if (null == menu) {
            throw new BizException(10000, "record.found.not");
        }
        List<TSysMenu> menuList = this.getMenuByPid(mid);
        if (menuList.size() > 0) {
            throw new BizException(10000, "del.sub.menu.first");
        }
        this.baseMapper.deleteById(menu);
        return true;
    }


    @Override
    @Transactional(rollbackFor = BizException.class)
    public Boolean saveRoleMenu(Integer rid, List<Integer> menuIds) {
        //拷贝备用
        List<Integer> needAddMenuIds = new ArrayList<>(menuIds);
        //获取角色原拥有的权限
        List<TSysRoleMenu> curRoleMenuList = this.getRoleMenuByRoleId(rid);
        List<Integer> curMenuIds = curRoleMenuList.stream().map(TSysRoleMenu::getMenuId).collect(Collectors.toList());
        //拷贝备用
        List<Integer> needDelMenuIds = new ArrayList<>(curMenuIds);
        //求差集新权限有老权限没有的ids（需要添加）
        needAddMenuIds.removeAll(curMenuIds);
        if (needAddMenuIds.size() > 0) {
            needAddMenuIds.forEach(needAddMenuId -> {
                TSysRoleMenu roleMenu = new TSysRoleMenu();
                roleMenu.setRoleId(rid);
                roleMenu.setMenuId(needAddMenuId);
                this.sysRoleMenuService.getBaseMapper().insert(roleMenu);
            });
        }
        //(需要删除)
        needDelMenuIds.removeAll(menuIds);
        if (needDelMenuIds.size() > 0) {
            /**
             * 获取列表
             */
            QueryWrapper<TSysRoleMenu> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("MENU_ID", needDelMenuIds);
            queryWrapper.eq("STATUS", 1);
            List<TSysRoleMenu> deleteList = this.sysRoleMenuService.getBaseMapper().selectList(queryWrapper);
            List<Integer> deleteIdList = deleteList.stream().map(TSysRoleMenu::getId).collect(Collectors.toList());
            this.sysRoleMenuService.getBaseMapper().deleteBatchIds(deleteIdList);
        }
        return true;
    }

    @Override
    public List<TSysMenu> getMenuList(Integer show) {
        if (show.equals(1)) {
            return this.getMenuListAndShow(show);
        }
        return this.getMenuList();
    }

    @Override
    public List<TSysMenu> getMenuByPids(List<Integer> pids, Integer show) {
        if (pids.size() > 0) {
            if (show.equals(1)) {
                return this.getMenuByPidsAndShow(pids, show);
            }
            return this.getMenuByPids(pids);
        }
        return new ArrayList<>();
    }

    @Override
    public List<TSysMenu> getMenuByPidsAndIds(List<Integer> pids, List<Integer> menuIds, Integer show) {
        if (pids.size() > 0) {
            if (show.equals(1)) {
                return this.getMenuByPidsAndMenuIdsAndShow(pids, menuIds, show);
            }
            return this.getMenuByPidsAndMenuIds(pids, menuIds);
        }
        return new ArrayList<>();
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByIds(List<Integer> ids) {
        /**
         * select m from Menu m where m.id in(:ids) and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("ID", ids);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public List<TSysMenu> getMenuByLevel(Integer level, Integer show) {
        if (show.equals(1)) {
            return this.getMenuByLevelAndShow(level, show);
        }
        return this.getMenuByLevel(level);
    }

    @Override
    public List<TSysMenu> getMenuByLevelAndIds(Integer level, List<Integer> menuIds, Integer show) {
        if (show.equals(1)) {
            return this.getMenuByLevelAndMenuIdsAndShow(level, menuIds, show);
        }
        return this.getMenuByLevelAndMenuIds(level, menuIds);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<TSysRoleMenu> getRoleMenuListByRoleId(Integer rid) {
        /**
         *  select rm from RoleMenu rm where rm.roleId = :roleId and rm.status = 1
         */
        QueryWrapper<TSysRoleMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ROLE_ID", rid);
        queryWrapper.eq("STATUS", 1);
        return this.sysRoleMenuService.getBaseMapper().selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public void changeShowStatus(TSysMenu menu, Integer show) {
        if (null != show) {
            //如果是子菜单隐藏不需要关心父级菜单
            if (menu.getPid() != 0 && show == 0) {
                //
            }
            //如果是子菜单显示父级菜单必须显示
            if (menu.getPid() != 0 && show == 1) {
                TSysMenu pMenu = this.getMenuById(menu.getPid());
                if (pMenu.getShow() != 1) {
                    pMenu.setShow(1);
                    this.baseMapper.updateById(pMenu);
                }
            }
            //如果是父级菜单隐藏那子菜单都必须隐藏
            if (menu.getPid() == 0 && show == 0) {
                List<TSysMenu> childMenu = this.getMenuByPid(menu.getId());
                childMenu.forEach(updateMenu -> {
                    updateMenu.setShow(0);
                    this.baseMapper.updateById(updateMenu);
                });
            }
            //如果父级菜单显示不需要关心子菜单
            if (menu.getPid() == 0 && show == 1) {
                //
            }
        }
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysRoleMenu> getRoleMenuByRoleId(Integer roleId) {
        /**
         *     select rm from RoleMenu rm where rm.roleId = :roleId and rm.status = 1
         */
        QueryWrapper<TSysRoleMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ROLE_ID", roleId);
        queryWrapper.eq("STATUS", 1);
        return this.sysRoleMenuService.getBaseMapper().selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByPid(Integer pid) {
        /**
         *     select m from Menu m where m.pid = :pid and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("PID", pid);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public TSysMenu getMenuById(Integer id) {
        /**
         *     select m from Menu m where m.id = :id and m.status = 1
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ID", id);
        queryWrapper.eq("STATUS", 1);
        return this.baseMapper.selectOne(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuList() {
        /**
         * select m from Menu m where m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuListAndShow(Integer show) {
        /**
         *     select m from Menu m where m.show = :show and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("`SHOW`", show);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByPidsAndMenuIds(List<Integer> pids, List<Integer> menuIds) {
        /**
         *   select m from Menu m where m.pid in(:pids) and m.id in(:menuIds) and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("PID", pids);
        queryWrapper.in("ID", menuIds);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByPidsAndMenuIdsAndShow(List<Integer> pids, List<Integer> menuIds, Integer show) {
        /**
         *  select m from Menu m where m.pid in(:pids) and m.id in(:menuIds) and m.show = :show and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("PID", pids);
        queryWrapper.in("ID", menuIds);
        queryWrapper.eq("`SHOW`", show);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByPids(List<Integer> pids) {
        /**
         *   select m from Menu m where m.pid in(:pids) and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("PID", pids);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByPidsAndShow(List<Integer> pids, Integer show) {
        /**
         *   select m from Menu m where m.pid in(:pids) and m.show = :show and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("PID", pids);
        queryWrapper.eq("`SHOW`", show);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByLevelAndMenuIds(Integer level, List<Integer> menuIds) {
        /**
         *   select m from Menu m where m.level = :level and m.id in(:menuIds) and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("`LEVEL`", level);
        queryWrapper.in("ID", menuIds);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);

    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByLevelAndMenuIdsAndShow(Integer level, List<Integer> menuIds, Integer show) {
        /**
         *   select m from Menu m where m.level = :level and m.id in(:menuIds) and m.show = :show and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("`LEVEL`", level);
        queryWrapper.in("ID", menuIds);
        queryWrapper.eq("`SHOW`", show);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);

    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByLevel(Integer level) {
        /**
         *   select m from Menu m where m.level = :level  and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("`LEVEL`", level);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByLevelAndShow(Integer level, Integer show) {
        /**
         *   select m from Menu m where m.level = :level and m.show = :show and m.status = 1 order by m.sort desc
         */
        QueryWrapper<TSysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("`LEVEL`", level);
        queryWrapper.eq("`SHOW`", show);
        queryWrapper.eq("STATUS", 1);
        queryWrapper.orderByDesc("SORT");
        return this.baseMapper.selectList(queryWrapper);
    }
}
